package com.avic.common.util;

import com.avic.controller.info.PlUpload;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.Map;

/**
 * @Author huangsheng on 2019/2/28
 */
@Slf4j
public class PlUploadUtils {

    public static void upload(PlUpload plupload, File pluploadDir, String fileName) {
        // 用户上传文件被分隔的总块数
        int chunks = plupload.getChunks();
        // 当前块，从0开始
        int nowChunk = plupload.getChunk();
        // 这里Request请求类型的强制转换可能出错，配置文件中向SpringIOC容器引入multipartResolver对象即可。
        MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest) plupload.getRequest();
        // 调试发现map中只有一个键值对
        Map<String, MultipartFile> multiFileMap = multipartHttpServletRequest.getFileMap();
        if (multiFileMap != null) {
            try {
                Iterator<String> iterator = multiFileMap.keySet().iterator();
                File targetFile = null;
                File tempFile = null;
                while (iterator.hasNext()) {
                    MultipartFile multipartFile = multiFileMap.get(iterator.next());
                    plupload.setMultipartFile(multipartFile);// 手动向Plupload对象传入MultipartFile属性值
                    targetFile = new File(pluploadDir, fileName);// 新建目标文件，只有被流写入时才会真正存在
                    if (chunks > 1) {// 用户上传资料总块数大于1，要进行合并
                        tempFile = new File(pluploadDir.getPath(), multipartFile.getName());
                        // 第一块直接从头写入，不用从末端写入
                        savePluploadFile(multipartFile.getInputStream(), tempFile, nowChunk == 0 ? false : true);

                        if (chunks - nowChunk == 1) {// 全部块已经上传完毕，此时targetFile因为有被流写入而存在，要改文件名字
                            tempFile.renameTo(targetFile);
                        }
                    } else {
                        // 只有一块，就直接拷贝文件内容
                        multipartFile.transferTo(targetFile);
                    }
                }
            } catch (IOException e) {
                log.error("上传文件发生错误 {}", e.getMessage());
            } catch (Exception e) {
                log.error("上传文件发生错误 {}", e.getMessage());
            }
        }
    }

    /**
     * 描述 : 写入文件到磁盘. <br>
     *
     * @param inputStream 数据流
     * @param tempFile    临时文件
     * @param flag        是否是追加，是的话需要在原来的基础上添加，否则直接写入
     * @author yjw@jusfoun.com
     * @date 2017年10月18日 上午9:32:15
     */
    private static void savePluploadFile(InputStream inputStream, File tempFile, boolean flag) {
        OutputStream outputStream = null;
        try {
            if (flag == false) {
                // 从头写入
                outputStream = new BufferedOutputStream(new FileOutputStream(tempFile));
            } else {
                // 从末端写入,追加
                outputStream = new BufferedOutputStream(new FileOutputStream(tempFile, true));
            }
            byte[] bytes = new byte[1024];
            int len = 0;
            while ((len = (inputStream.read(bytes))) > 0) {
                outputStream.write(bytes, 0, len);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                outputStream.close();
                inputStream.close();
            } catch (IOException e) {
            }
        }
    }
}
